package com.shudes.eval;

import java.math.*;
import java.util.*;

import com.shudes.util.*;

public class Combinatorial<T extends Comparable> {

	protected TreeSet<T> collection;
	
	public Combinatorial(Collection<T> collection) {
		this.collection =  new TreeSet<T>(collection); 
	} 
		
	public Set<Set<T>> generate(int size) { 
		List<List<T>> subResult; 
		Set<Set<T>> result; 
		
		subResult = new ArrayList<List<T>>(); 
		for(T o : this.collection) { 
			subResult = this.cross(o, subResult, size); 
		}
		
		this.removeInvalids(subResult, size); 

		result = new HashSet<Set<T>>(); 
		for(List<T> list : subResult) { 
			result.add(new TreeSet<T>(list)); 
		}
		
//		System.out.println("final result: size=" + result.size() + "\n" + result); 		
		return result; 
	}
	
	public Long getCombinations(int size) { 
		return DiscreteUtils.combinations(this.collection.size(), size).longValue();
	}
	
	protected List<List<T>> cross(T t, List<List<T>> subResult, int size) { 
		List<List<T>> result; 
		List<T> sub;				

		result = new ArrayList<List<T>>();
		result.addAll(subResult); 
		
		sub = new ArrayList<T>();
		sub.add(t); 
		result.add(sub); 			
		
		for(List<T> s : subResult) {
			if(s.size()<size) {
				sub =  new  ArrayList<T>();
				sub.add(t); 
				sub.addAll(s); 
				result.add(sub);
			}
						
		}				

//		System.out.println(" cross -> size=" + size + ": " + object + "  x " + subResult + " \n\t -> " + result); 
		
		return result; 
	}

	protected void removeInvalids(List<List<T>> result, int size) { 
		for(Iterator<List<T>> it = result.iterator(); it.hasNext();) { 
			List<T> list = it.next(); 
			if(list.size()!=size) { 
				it.remove();
			}
		}
	}

}
